# coding=utf-8

from shorturls.baseconv import base62
from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from django.core.cache import cache
from django_autoslug.fields import AutoSlugField
from django.template.defaultfilters import slugify
from django.db.models.aggregates import Sum, Max
from django.db.models import signals
from django.conf import settings
from django.contrib.auth.signals import user_logged_in
from persistent_messages.models import Message
from urllib import basejoin
from datetime import datetime, timedelta
import urllib2, os
from mitems.tools.utils import resize_picture, random_number,\
    random_string, get_country_with_ip, make_upload_path, get_timezone_with_ip
from django_countries import CountryField
import logging
import shutil

log = logging.getLogger('minutes')

CATEGORY_CHOICES = (
    ('personal', 'Personal'),
    ('news', 'News'),
    ('entertainment', 'Entertainment'),
    ('sports', 'Sports'),
    ('technology', 'Technology'),
    ('lifestyle', 'Lifestyle'),
    ('business', 'Business'),
    ('travel', 'Travel',),
)

TYPE_CHOICES = (
    ('status', 'status'),
    ('picture', 'picture'),
    ('video', 'video'),
    ('internet link', 'internet link'),

)

GROUP_CHOICES = (
    ('regular', 'regular'),
    ('hidden-advertising', 'hidden-advertising'),
    ('negative', 'negative'),
    ('spam', 'spam'),
)

GENDER_CHOISE = (
    ('male', 'male'),
    ('female', 'female'),
)

PROVIDER_CHOISE = (
    ('facebook', 'facebook'),
    ('twitter', 'twitter'),
)

def first_day_of_week():
    now = datetime.today()
    first_day = now-timedelta(days=now.weekday())
    return datetime(first_day.year, first_day.month, first_day.day)


class Item_category(models.Model):

    category = models.CharField(max_length=50, choices=CATEGORY_CHOICES)

    def natural_key(self):
        return self.category

    def __unicode__(self):
        return "%s" % self.category

    class Meta:
        verbose_name_plural = "Categories"


class Item_type(models.Model):

    type = models.CharField(max_length=50, choices=TYPE_CHOICES)

    def natural_key(self):
        return self.type

    def __unicode__(self):
        return "%s" % self.type

    class Meta:
        verbose_name_plural = "Types"


class Item_group(models.Model):

    group = models.CharField(max_length=50, choices=GROUP_CHOICES)
    scope = models.FloatField()

    def natural_key(self):
        return self.group

    def __unicode__(self):
        return "%s" % self.group

    class Meta:
        verbose_name_plural = "Groups"


class UserProfile(User, models.Model):

    slug = AutoSlugField(populate_from=('username',), unique=True,
                         db_index=True, null=True, blank=True)
    reputation = models.FloatField(default=1)
    airtime = models.PositiveIntegerField(default=80)
    airtime_avg = models.FloatField(default=0)
    gender = models.CharField(max_length=10, blank=True, null=True, choices=GENDER_CHOISE)
    avatar = models.ImageField(upload_to=make_upload_path, blank=True, null=True)
    location = CountryField(blank=True, null=True)
    locale = models.CharField(max_length=10, blank=True, null=True,
                              default='en', choices=settings.LANGUAGES)
    mobile_email = models.EmailField(blank=True, null=True)
    birthday = models.DateField(blank=True, null=True)
    interest = models.CharField(max_length=256, blank=True, null=True)
    fb_auto_post = models.BooleanField(default=False)
    is_bot = models.BooleanField(default=False)
    twitter_allow = models.BooleanField(default=True)
    google_email = models.EmailField(blank=True, null=True)
    timezone = models.CharField(max_length=64, blank=True, null=True)
    is_elite = models.BooleanField(default=False)
    auto_airtime = models.BooleanField(default=True)
    objects = User.objects

    def __unicode__(self):
        return self.username.encode('utf8', 'replace').decode('utf8', 'replace')

    def get_profile(self):
        return self

    def natural_key(self):
        return self.username

    def get_facebook_token(self):
        try:
            user = self.social_auth.filter(provider='facebook').order_by('-id')[:1].get()
        except ObjectDoesNotExist:
            return None
        return user.extra_data.get('access_token')

    def get_twitter_tokens(self):
        try:
            user = self.social_auth.filter(provider='twitter').order_by('-id')[:1].get()
        except ObjectDoesNotExist:
            return None
        tokens = dict([token.split('=') for token in
                       user.extra_data.get('access_token').split('&')])
        return tokens.get('oauth_token'), tokens.get('oauth_token_secret')

    def get_google_tokens(self):
        try:
            user = self.social_auth.filter(provider='google-oauth', uid=self.google_email)[:1].get()
        except ObjectDoesNotExist:
            return None
        tokens = dict([token.split('=') for token in
                       user.extra_data.get('access_token').split('&')])
        return tokens.get('oauth_token'), tokens.get('oauth_token_secret')

    def get_auth_providers(self):
        try:
            providers = self.social_auth.values_list('provider', flat=True).distinct()
        except Exception:
            return None
        return providers

    def get_followers(self):
        return list(set([ user.follower for user in self.followers.order_by('-id')]))

    def get_follows(self):
        return list(set([ user.follow for user in self.follows.order_by('-id')]))

    def is_following(self, user):
        try:
            Follower.objects.get(follower=self, follow=user)
            return True
        except Follower.DoesNotExist:
            return False

    def short_username(self):
        username = self.get_username()
        if len(username) > settings.USERNAME_LENGTH:
            size = len(username + '...') - settings.USERNAME_LENGTH
            username = u'%s...' % username[:-size]
        return username

    def live_minutes_week(self):
        start_day = first_day_of_week()
        week_items = self.created_by.exclude(time_expired__lte=start_day)
        minutes = 0
        for item in week_items:
            current_time = datetime.now()
            start_time = item.created if item.created>start_day else start_day
            end_time = item.time_expired if item.time_expired<current_time else current_time
            live_time = end_time-start_time
            minutes += (live_time.seconds+live_time.days*24*3600)//60
        return minutes

    def live_current(self):
        return self.created_by.filter(slumped=False).count()

    def get_username(self):
        if not self.first_name or not self.last_name:
            return self.username
        else:
            return "%s %s" % (self.first_name, self.last_name)

    def get_actions_total(self):
        actions = ( self.created_by.count() +
                    self.users_comment.count() +
                    self.users_like.count() +
                    self.users_share.count() +
                    len(self.get_follows())
        )
        return actions

    def had_activity(self):
        return  bool( self.created_by.count() or
                  self.users_comment.count() or
                  self.users_like.count() or
                  self.users_share.count() or
                  len(self.get_follows())
        )

    def get_absolute_url(self):
        return basejoin(settings.SITE_URL, '/user/%s/' % self.username)

    def get_last_comment(self):
        try:
            return self.users_comment.order_by('-id')[:1].get()
        except ObjectDoesNotExist:
            return None

    def get_notifications_count(self):
        return Message.objects.filter(user=self, closed=False).count()

    def get_notifications(self):
        return Message.objects.filter(user=self, closed=False)


class ItemManager(models.Manager):

    def get_query_set(self):
        return super(ItemManager, self).get_query_set().filter(is_active=True)


class ItemModel(models.Model):

    objects = ItemManager()
    admin = models.Manager()

    class Meta:
        abstract = True


class Item(ItemModel):

    message = models.CharField(max_length=256)
    slug = AutoSlugField(populate_from=('message',), unique=True,
                         db_index=True, null=True, blank=True)
    description = models.CharField(max_length=256, blank=True)
    tag = models.CharField(max_length=256, blank=True)
    created_by = models.ForeignKey(UserProfile, related_name='created_by')
    updated_by = models.ForeignKey(UserProfile, related_name='updated_by')
    created = models.DateTimeField(editable=False, default=datetime.now)
    updated = models.DateTimeField(editable=False, default=datetime.now)
    category = models.ForeignKey(Item_category, blank=False, default=1)
    type = models.ForeignKey(Item_type, default=1)
    group = models.ForeignKey(Item_group, default=1)
    time_total = models.PositiveIntegerField(default=0)
    time_expired = models.DateTimeField(default=datetime.now)
    unique_users = models.FloatField(default=0.0001)
    actions_total = models.PositiveIntegerField(default=0)
    actions_total_visitors = models.PositiveIntegerField(default=0)
    actions_total_foreign = models.PositiveIntegerField(default=0)
    more_cycle = models.PositiveIntegerField(default=0)
    impact = models.FloatField(default=0)
    signal_strength = models.FloatField(default=0)
    score = models.FloatField(default=0)
    location = CountryField(blank=True, null=True)
    slumped = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    is_mail = models.BooleanField(default=False)
    is_feed = models.BooleanField(default=False)
    is_reposted = models.BooleanField(default=False)
    elite_like = models.BooleanField(default=False)
    feed_id = models.URLField(max_length=500, blank=True, null=True)
    twitter_sent = models.BooleanField(default=False)

    def __unicode__(self):
        return self.message

    def natural_key(self):
        return self.message

    def get_absolute_url(self, chapter=None):
        local_part = 'item/%s/%s/' % (chapter, self.slug or slugify(self.message))\
            if chapter else 'item/%s/' % self.slug or slugify(self.message)
        return basejoin(settings.SITE_URL, local_part)

    def users_like_it(self):
        return [ like.user for like in self.items_like.all() ]

    def item_airtime_count(self):
        return self.items_airtime.aggregate(count=Sum('count')).get('count')  or 0

    def get_cycle_time(self):
        diff_time = datetime.now()-self.created
        seconds_elapse = diff_time.days*24*3600 + diff_time.seconds
        start_time = self.created+timedelta(
            seconds=(seconds_elapse//settings.CYCLE_SECONDS)*settings.CYCLE_SECONDS)
        end_time = start_time + timedelta(seconds=settings.CYCLE_SECONDS)
        return start_time, end_time

    def item_airtime_current(self):
        cycle_time = self.get_cycle_time()
        return self.items_airtime.filter(time__range=cycle_time).\
               aggregate(count=Sum('count')).get('count')  or 0

    def item_airtime_left(self):
        cycle_time = self.get_cycle_time()
        airtime_current =  self.items_airtime.filter(time__range=cycle_time).\
               aggregate(count=Sum('count')).get('count')  or 0
        airtime_left = settings.AIRTIME_PER_CYCLE - airtime_current
        if airtime_left < 0:
            airtime_left = 0
        return min(self.created_by.airtime, airtime_left)

    def item_ies_current(self):
        cycle_time = self.get_cycle_time()
        ies =  ((self.items_airtime.filter(time__range=cycle_time).\
               aggregate(count=Sum('count')).get('count')  or 0) +
               self.items_comment.filter(time__range=cycle_time).count() +
               self.items_like.filter(time__range=cycle_time).count() +
               self.items_share.filter(time__range=cycle_time).count())
        if ies > 8:
            ies = 8
        return ies

    def item_ies_ranges(self):
        ies = self.item_ies_current()
        return range(0,ies), range(ies,8)

    def item_get_opacity(self):
        diff_time = self.time_expired - datetime.now()
        seconds_left = diff_time.seconds + diff_time.days*24*3600
        if seconds_left <=0:
            return settings.MIN_OPACITY
        if seconds_left <= 20:
            opacity = settings.MIN_OPACITY+(1-settings.MIN_OPACITY)*(seconds_left/20.0)
            return "%.2f" % opacity
        return 1

    def get_unique_users(self):
        unique = len(set(list(self.items_comment.values_list('user', flat=True).distinct())+
                         list(self.items_like.values_list('user', flat=True).distinct())+
                         list(self.items_share.values_list('user', flat=True).distinct()))) or 0.0001
        return unique

    def get_scope(self):
        comments = self.items_comment.count()
        likes = self.items_like.count()
        shares = self.items_share.count()
        actions_total_visitors = comments+likes+shares
        unique_users = self.get_unique_users()
        impact = 1.0/((actions_total_visitors+1)/float(unique_users))
        diff_time = datetime.now()-self.created
        time_total = diff_time.seconds + diff_time.days*24*3600
        signal_strength = (float(time_total)/60)/(actions_total_visitors+1)
        score = ((0.5*impact+0.5*signal_strength)*
                          self.group.scope*self.created_by.reputation)
        return score

    def if_slumped(self):
        comments = self.items_comment.count()
        likes = self.items_like.count()
        shares = self.items_share.count()
        airtime = self.items_airtime.aggregate(count=Sum('count')).get('count') or 0
        actions_total = comments+likes+shares+airtime
        more_cycle = actions_total//8
        time_expired = self.created+timedelta(seconds=(more_cycle+1)*settings.CYCLE_SECONDS)
        slumped = True if datetime.now() >= time_expired else False
        return slumped

    def get_time_of_life(self):
        if self.slumped:
            return self.time_total//60
        diff_time = datetime.now()-self.created
        return (diff_time.seconds+diff_time.days*24*3600)//60

    def responded_users(self):
        comments = list(self.items_comment.values('user').annotate(time=Max('time')).order_by('-time')[:16])
        likes = list(self.items_like.values('user').annotate(time=Max('time')).order_by('-time')[:16])
        shares = list(self.items_share.values('user').annotate(time=Max('time')).order_by('-time')[:16])
        users = list(set([item['user'] for item in
                          sorted((comments+likes+shares), key=lambda a:a['time'])]))[:16]
        return UserProfile.objects.filter(pk__in=users)

    def question(self):
        return [ question.user for question in self.items_question.all() ]

    def get_small_image(self):
        try:
            return self.images.get(size='small')
        except ObjectDoesNotExist:
            return False

    def get_big_image(self):
        try:
            return self.images.get(size='big')
        except ObjectDoesNotExist:
            return False

    def get_short_url(self):
        key = '%s.%s' % (self._meta.app_label, self.__class__.__name__.lower())
        prefix = dict((m,p) for p,m in settings.SHORTEN_MODELS.items()).get(key)
        tiny = base62.from_decimal(self.pk)
        return basejoin(settings.SHORT_BASE_URL, prefix+tiny)

    def is_dev_story(self=0):
        search = dict(created__gte=(datetime.now()-timedelta(seconds=settings.DEV_STORIES_TIME_FRAME)),
                    category = self.category)
        return self in Item.objects.filter(**search).order_by('-score')[:8]

    def get_twitter_message(self):
        return settings.TWITTER_MESSAGE % (self.message, self.get_short_url())


class Follower(models.Model):

    follower = models.ForeignKey(UserProfile, related_name='follows')
    follow = models.ForeignKey(UserProfile, related_name='followers')

    def __unicode__(self):
        return u"follower %s - follows %s" % (self.follower, self.follow)

    def natural_key(self):
        return u"%s-%s" % (self.follower, self.follow)

    class Meta:
        unique_together = ('follower', 'follow')


class Like(models.Model):

    user = models.ForeignKey(UserProfile, related_name='users_like')
    item = models.ForeignKey(Item, related_name='items_like')
    time = models.DateTimeField(auto_now_add=True)

    def __unicode__(self):
        return u"%s likes %s" % (self.user, self.item)

    def natural_key(self):
        return u"%s-%s" % (self.user, self.item)

    class Meta:
        unique_together = ('user', 'item')


class Share(models.Model):

    user = models.ForeignKey(UserProfile, related_name='users_share')
    item = models.ForeignKey(Item, related_name='items_share')
    provider = models.CharField(max_length=50, choices=PROVIDER_CHOISE, blank=True, null=True)
    time = models.DateTimeField(auto_now_add=True)

    def __unicode__(self):
        return u"%s shares %s" % (self.user, self.item)

    def natural_key(self):
        return u"%s-%s" % (self.user, self.item)


class Inquestion(models.Model):

    user = models.ForeignKey(UserProfile, related_name='users_question')
    item = models.ForeignKey(Item, related_name='items_question')
    time = models.DateTimeField(auto_now_add=True)

    def __unicode__(self):
        return u"%s questioned %s" % (self.user, self.item)

    def natural_key(self):
        return u"%s-%s" % (self.user, self.item)

    class Meta:
        unique_together = ('user', 'item')


class Comment(models.Model):

    comment = models.CharField(max_length=256)
    user = models.ForeignKey(UserProfile, related_name='users_comment')
    item = models.ForeignKey(Item, related_name='items_comment')
    time = models.DateTimeField(auto_now_add=True)

    def natural_key(self):
        return self.comment

    def __unicode__(self):
        return u"%s comments %s for %s" % (self.user, self.comment, self.item)

    def users_like_it(self):
        return [ like.user for like in self.comment_like.all() ]


class CommentLike(models.Model):

    user = models.ForeignKey(UserProfile, related_name='users_comment_like')
    comment = models.ForeignKey(Comment, related_name='comment_like')
    time = models.DateTimeField(auto_now_add=True)

    def __unicode__(self):
        return u"%s likes %s" % (self.user, self.comment)

    def natural_key(self):
        return u"%s-%s" % (self.user, self.comment)

    class Meta:
        unique_together = ('user', 'comment')



class Airtime(models.Model):

    count = models.PositiveIntegerField(default=1)
    user = models.ForeignKey(UserProfile, related_name='users_airtime')
    item = models.ForeignKey(Item, related_name='items_airtime')
    time = models.DateTimeField(auto_now_add=True)

    def natural_key(self):
        return u"%s-%s-%s" % (self.count, self.user, self.item)

    def __unicode__(self):
        return u"%s, %s airtime for %s" % (self.user, self.count, self.item)


class ItemImage(models.Model):

    item = models.ForeignKey(Item, related_name='images')
    image = models.ImageField(upload_to=make_upload_path)
    size = models.CharField(max_length=256, default='small')

    def __unicode__(self):
        return basejoin(settings.SITE_URL, self.image.url)

    def get_absolute_url(self):
        return basejoin(settings.SITE_URL, self.image.url)


class Notification(models.Model):

    user = models.ForeignKey(UserProfile, related_name='notification', unique=True)
    someone_comment_me_site = models.BooleanField(default=False,
                                                verbose_name="Comments on an item I submitted or likes it")
    someone_comment_me_email = models.BooleanField(default=True,
                                                verbose_name="Comments on an item I submitted or likes it")
    someone_follow_me_site = models.BooleanField(default=False,
                                                verbose_name="Follows me")
    someone_follow_me_email = models.BooleanField(default=True,
                                                verbose_name="Follows me")
    follow_submit_item_site = models.BooleanField(default=True,
                                                verbose_name="Submits an item")
    follow_submit_item_email = models.BooleanField(default=True,
                                                verbose_name="Submits an item")
    follow_comment_item_site = models.BooleanField(default=False,
                                                verbose_name="Comments on an item or likes one")
    follow_comment_item_email = models.BooleanField(default=False,
                                                verbose_name="Comments on an item or likes one")
    minutes_2_site = models.BooleanField(default=True,
                                    verbose_name="Only has 2 minutes to stay LIVE")
    minutes_2_email = models.BooleanField(default=True,
                                    verbose_name="Only has 2 minutes to stay LIVE")
    news_site = models.BooleanField(default=True,
                                    verbose_name="Launch new features, promotions or other good stuff")
    news_email = models.BooleanField(default=True,
                                    verbose_name="Launch new features, promotions or other good stuff")


from mitems.tools.notify import notify_web, EMAIL_MESSAGE, notify_comment,\
    notify_follow_me, notify_item_mail, notify_airtime, notify_follow_submit,\
    notify_follow_comment, notify_login, notify_slump_in_2
from mitems.tools.utils import elite_random_airtime

from social_auth.signals import pre_update, socialauth_registered
from social_auth.backends.facebook import FacebookBackend
from social_auth.backends.twitter import TwitterBackend
from social_auth.backends.google import GoogleOAuthBackend

def change_item(item):
    """Make item calculations"""
#    if item.slumped: return
    comments = item.items_comment.count()
    likes = item.items_like.count()
    shares = item.items_share.count()
    airtime = item.items_airtime.aggregate(count=Sum('count')).get('count') or 0
    item.actions_total = comments+likes+shares+airtime
    item.actions_total_visitors = comments+likes+shares
    item.more_cycle = item.actions_total//8
    item.time_expired = item.created+timedelta(seconds=(item.more_cycle+1)*8*60)
    item.slumped = True if datetime.now() >= item.time_expired else False
    if item.slumped:
        diff_time = item.time_expired-item.created
    else:
        diff_time = datetime.now()-item.created
    item.time_total = diff_time.seconds + diff_time.days*24*3600
    if item.slumped: return
    unique_users = item.get_unique_users()
    item.unique_users = unique_users
    item.impact = min(1.0/((item.actions_total_visitors or 1)/float(unique_users)),
                      settings.MAX_UI)
    item.actions_total_foreign = (item.items_comment.exclude(user=item.created_by).count()+
                                  item.items_like.exclude(user=item.created_by).count()+
                                  item.items_share.exclude(user=item.created_by).count()
    )
    if item.actions_total_foreign:
        try:
            item.signal_strength = min(10/(((float(item.time_total)/60)/(item.actions_total_visitors or 1))),
                                       settings.MAX_ISS)/settings.MAX_ISS
        except ZeroDivisionError:
            item.signal_strength = 0
    else:
        item.signal_strength = 0
    item.score = ((0.5*item.impact+0.5*item.signal_strength)*
                      item.group.scope*item.created_by.reputation)


def update_picture(sender, **kwargs):
    instance = kwargs.get('instance')
    filename = instance.image.path
    if settings.DEBUG:
        log.info("change picture %s from %s" % (filename, instance))
    if instance.size == 'small':
        resize_picture(filename, settings.IMAGE_SIZE)
    if instance.size == 'big':
        resize_picture(filename, settings.IMAGE_SIZE_STORY)


def delete_picture(sender, **kwargs):
    instance = kwargs.get('instance')
    filename = instance.image.path
    try:
        os.remove(filename)
    except OSError:
        pass


def pre_save_item(sender, **kwargs):
    item = kwargs.get('instance')
    if not item.id and not item.created:
        item.created = datetime.now()
    change_item(item)


def post_save_item(sender, created, **kwargs):
    item = kwargs.get('instance')
    cache.clear()
    if created:
        if item.is_mail:
            notify_item_mail(item)
        notify_follow_submit(item)


def post_delete_item(sender, **kwargs):
    """Clear cache after item deleting"""
    item = kwargs.get('instance')
    if not item.slumped:
        cache.clear()


def save_user(sender, **kwargs):
    user = kwargs.get('instance')
    if user.avatar:
        resize_picture(user.avatar.path, settings.IMAGE_SIZE)


def delete_user(sender, **kwargs):
    user = kwargs.get('instance')
    user.social_auth.all().delete()
    try:
        shutil.rmtree(os.path.join(settings.MAIL_DIR, user.mobile_email.split('@')[0]))
    except Exception as err:
        log.error(err)
    if user.avatar:
        filename = user.avatar.path
        try:
            os.remove(filename)
        except OSError:
            pass

def user_messages(sender, request, user, **kwargs):
    timezone, location = None, None
    if not user.location:
        location = get_country_with_ip(request.META.get('REMOTE_ADDR', '127.0.0.1'))
    if not user.timezone:
        timezone = get_timezone_with_ip(request.META.get('REMOTE_ADDR', '127.0.0.1'))
    if user.location != location or user.timezone != timezone:
        user.location = location
        user.timezone = timezone
        user.save()
    if not user.email:
        notify_web(request.user, EMAIL_MESSAGE)


def change_related_items(sender, **kwargs):
    try:
        instance = kwargs.get('instance')
        item = instance.item
        if settings.DEBUG:
            log.info("change item %s from %s" % (item, instance))
    except Exception:
        return
    if sender == Comment:
        if instance.user != instance.item.created_by:
            notify_comment(instance)
        notify_follow_comment(instance)
    if sender == Like:
        if instance.user != instance.item.created_by:
            notify_comment(instance, like=True)
        elif instance.user.is_elite:
            instance.item.elite_like = True
        notify_follow_comment(instance, like=True)
    change_item(item)
    item.save()


def change_related_users(sender, **kwargs):
    try:
        instance = kwargs.get('instance')
        user = instance.user
        if settings.DEBUG:
            log.info("change user %s from %s" % (user, instance))
    except Exception:
        return
    airtime = user.users_airtime.aggregate(count=Sum('count')).get('count') or 0
    try:
        user.airtime_avg = airtime/float(user.created_by.count())
    except ZeroDivisionError:
        user.airtime_avg = 0
    if sender == Airtime:
        if not user.is_bot and not user.is_superuser:
            user.airtime -= instance.count
            if user.airtime <= settings.MIN_AIRTIME_COUNT:
                notify_airtime(user)
    try:
        user.save()
    except Exception:
        pass


def follow_notify(sender, **kwargs):
    instance = kwargs.get('instance')
    notify_follow_me(instance.follower, instance.follow)


# airtime signals
signals.post_save.connect(
    change_related_items, sender=Airtime,
    dispatch_uid='save_airtime_item')
signals.post_save.connect(
    change_related_users, sender=Airtime,
    dispatch_uid='save_airtime_user')
signals.post_delete.connect(
    change_related_items, sender=Airtime,
    dispatch_uid='delete_airtime_item')
signals.post_delete.connect(
    change_related_users, sender=Airtime,
    dispatch_uid='delete_airtime_user')

# comment signals
signals.post_save.connect(
    change_related_items, sender=Comment,
    dispatch_uid='save_comment_item')
signals.post_delete.connect(
    change_related_items, sender=Comment,
    dispatch_uid='delete_comment_item')

# like signals
signals.post_save.connect(
    change_related_items, sender=Like,
    dispatch_uid='save_like_item')
signals.post_delete.connect(
    change_related_items, sender=Like,
    dispatch_uid='delete_like_item')

# share signals
signals.post_save.connect(
    change_related_items, sender=Share,
    dispatch_uid='save_share_item')

signals.post_delete.connect(
    change_related_items, sender=Share,
    dispatch_uid='delete_share_item')

#ItemImage save
signals.post_save.connect(
    update_picture, sender=ItemImage,
    dispatch_uid='convert_image')

#ItemImage delete
signals.pre_delete.connect(
    delete_picture, sender=ItemImage,
    dispatch_uid='delete_image')

#Item save
signals.pre_save.connect(
    pre_save_item, sender=Item,
    dispatch_uid='pre_save_item')

signals.post_save.connect(
    post_save_item, sender=Item,
    dispatch_uid='post_save_item')

#Item delete
signals.post_delete.connect(
    post_delete_item, sender=Item,
    dispatch_uid='post_delete_item')

#Inappropiate signals
signals.post_save.connect(
    change_related_items, sender=Inquestion,
    dispatch_uid='save_inappropriate_item')

signals.post_delete.connect(
    change_related_items, sender=Inquestion,
    dispatch_uid='delete_inappropriate_item')

#Follow signals
signals.post_save.connect(
    follow_notify, sender=Follower,
    dispatch_uid='follow_notify')

# User save
signals.post_save.connect(
    save_user, sender=UserProfile,
    dispatch_uid='save_user')

# User delete
signals.pre_delete.connect(
    delete_user, sender=UserProfile,
    dispatch_uid='delete_user')

#Message for user after login
user_logged_in.connect(user_messages)

def save_avatar(url):
    destination_file = os.path.join(settings.MEDIA_ROOT, make_upload_path())
    try:
        with open(destination_file, 'wb') as destination:
            destination.write(urllib2.urlopen(url).read())
        return os.path.basename(destination_file)
    except Exception:
        return None

def facebook_extra_values(sender, user, response, details, **kwargs):
    if not user.gender:
        user.gender = response.get('gender', '')
    if not user.avatar:
        user.avatar = save_avatar(settings.FACEBOOK_PHOTO_URL % response.get('id'))
    if not user.email:
        user.email = response.get('email', '')
    if not user.birthday:
        try:
            user.birthday = datetime.strptime(response.get('birthday', ''), '%m/%d/%Y')
        except Exception:
            pass
    if not user.interest:
        user.interest = response.get('interests', '')
    if not user.first_name or not user.last_name:
        user.first_name = response.get('first_name', '')
        user.last_name = response.get('last_name', '')
    if not user.username and user.first_name and user.last_name:
        user.username = '%s.%s' % (user.first_name.lower(), user.last_name.lower())
    if not user.locale:
        locale = response.get('locale')
        if locale:
            user.locale = locale.split('_')[0]
    return False

def new_users_handler(sender, user, response, details, **kwargs):
    first_name = response.get('first_name', '').lower()
    last_name = response.get('last_name', '').lower()
    if not first_name or not last_name:
        try:
            first_name, last_name = response.get('name', '').lower().split()[0:2]
        except Exception:
            user.username = (slugify(user.username) or "user-%s" % random_number(4))[:settings.MAX_USERNAME_LENGTH]
    if first_name and last_name:
        username = ('%s.%s' % (slugify(first_name),
                               slugify(last_name)) or "user-%s" % random_number(4))[:settings.MAX_USERNAME_LENGTH]
        try:
            while True:
                UserProfile.objects.get(username=username)
                username = '%s%s' % (username, random_string(2))
        except UserProfile.DoesNotExist:
            pass
        user.username = username
    user.username = user.username[:settings.MAX_USERNAME_LENGTH]
    email = getattr(user, 'email', None)
    if email and len(email) > settings.MAX_EMAIL_LENGTH:
        user.email = ''
    user.mobile_email = '%s%s@%s' % (user.username, random_number(4), settings.MOBILE_DOMAIN)
    Notification(user=user).save()
    notify_login(user)
    return False


def twitter_extra_values(sender, user, response, details, **kwargs):
    return True

def google_extra_values(sender, user, response, details, **kwargs):
    user.google_email = response.get('email')
    return True

# social-auth signals
pre_update.connect(facebook_extra_values, sender=FacebookBackend)
pre_update.connect(twitter_extra_values, sender=TwitterBackend)
pre_update.connect(google_extra_values, sender=GoogleOAuthBackend)
socialauth_registered.connect(new_users_handler, sender=None)

#Update items
def update_items():
    items = Item.objects.filter(slumped=False)
    for item in items.iterator():
        item.save()

#Notify items
def notify_in_2_items():
    elite_airtime()
    search = dict(slumped=False, time_expired__lte=(datetime.now()+timedelta(seconds=60*2)))
    notify_slump_in_2(Item.objects.filter(**search))

def get_superuser():
    try:
        return UserProfile.objects.filter(is_superuser=True)[:1].get()
    except ObjectDoesNotExist:
        return

# Add airtime for elite users
def elite_airtime():
    elite_items = Item.objects.filter(slumped=False, created_by__is_elite=True,
                                      created_by__auto_airtime=True, elite_like=False,
                                      time_expired__lte=(datetime.now()+timedelta(seconds=60*2)))
    airtime_user = get_superuser()
    if airtime_user:
        for item in elite_items.iterator():
            Airtime(user=item.created_by, item=item, count=elite_random_airtime()).save()